﻿using SuperX.Common.Collection;
using SuperX.Common;
using SuperX.Common.Log;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading;
using SuperX.DataService.Abstract;
using System.Timers;
using NLog.LayoutRenderers;
using System.Drawing;
using System.Linq;
using static System.Net.Mime.MediaTypeNames;
using System.Security.Cryptography;
using SuperX.DataService.Helper;
using NPOI.SS.Formula.Functions;
using System.Data.SqlTypes;
using System.Data;
using NPOI.SS.UserModel;
using SuperX.Helper;
using System.Diagnostics;

namespace SuperX.DataService
{
    public abstract class AnalysisBase
    {
        public AnalysisDriverBase Parent { get; }

        public bool IsConnect
        { get { return _isConnect; } }

        private bool _isConnect = false;

        protected List<string> LogBuffer = new List<string>();

        protected long OffsetPostion;

        public bool IsRunning
        { get { return _isRunning; } }

        private bool _isRunning;

        private bool _scanThreadStatus;

        private bool _historyExpireThreadStatus;

        [JsonIgnore]
        public FileAnalysisConfig Config { get; set; }

        public AnalysisBase(AnalysisDriverBase parent)
        {
            Parent = parent;
        }

        public void Init()
        {
            try
            {
                ProcessedInit();
            }
            catch (Exception ex)
            {
                Logger.ErrorException(ex);
            }
        }

        public void Start()
        {
            _isRunning = false;
            while (Config.Enabled && _scanThreadStatus || (Config.IsBackup && _historyExpireThreadStatus))
            {
                Thread.Sleep(50);
            }
            _isRunning = true;
            if (Config.Enabled)
            {
                var scanThread = new Thread(Scan) { IsBackground = true };
                scanThread.Start();
            }
            if (Config.IsBackup)
            {
                var historyExpireThread = new Thread(HistoryDelete) { IsBackground = true };
                historyExpireThread.Start();
            }
        }

        public void Stop()
        {
            _isRunning = false;
        }

        public abstract void ProcessedInit();

        private void Scan()
        {
            _scanThreadStatus = true;
            while (_isRunning)
            {
                try
                {
                    AnalysisFiles();
                }
                catch (Exception ex)
                {
                    Logger.ErrorException(ex);
                }
                finally
                {
                    Thread.Sleep(Config.ReadCycle);
                }
            }
            _scanThreadStatus = false;
        }

        private void AnalysisFiles()
        {
            var files = GetNewFiles();
            SetConnect();
            foreach (var file in files)
            {
                if (!_isRunning) break;
                bool ReadSucceed = LogProcessed(file);
                if (ReadSucceed && Config.IsDbCache)
                {
                    SaveRecord();
                    if (ReadSucceed && Config.IsBackup) BackupFile(file);
                }
            }
        }

        protected virtual void SetConnect()
        {
        }

        private void HistoryDelete()
        {
            _historyExpireThreadStatus = true;
            while (_isRunning)
            {
                try
                {
                    DeleteHistoryFiles();
                }
                catch (Exception ex)
                {
                    Logger.ErrorException(ex);
                }
                finally
                {
                    Thread.Sleep(Config.ReadCycle);
                }
            }
            _historyExpireThreadStatus = false;
        }

        private void DeleteHistoryFiles()
        {
            if (!Directory.Exists(Config.HistoryFileConfig.LogLocation)) return;
            var files = GetFiles(Config.HistoryFileConfig.LogLocation, 1);
            double dayDiff = string.Format("{0}{1}", "-", Config.LogExpireDay.ToString()).ObjToDouble();
            var expireTime = DateTime.Now.AddDays(dayDiff);
            foreach (var file in files)
            {
                if (_isRunning) break;
                if (file.LastWriteTime < expireTime)
                {
                    try
                    {
                        File.Delete(file.FullName);
                    }
                    catch
                    {
                        continue;
                    }
                }
            }
        }

        /// <summary>
        /// 备份
        /// </summary>
        /// <param name="file"></param>
        public virtual void BackupFile(FileInfo file)
        {
            var destFileName = string.Format("{0}_{1}", DateTime.Now.ToString("yyyyMMddHHmmss"), file.Name);
            var destFileFullName = Path.Combine(Config.HistoryFileConfig.LogLocation, destFileName);
            try
            {
                if (!Directory.Exists(Config.HistoryFileConfig.LogLocation))
                {
                    Directory.CreateDirectory(Config.HistoryFileConfig.LogLocation);
                }
                if (!Directory.Exists(Config.HistoryFileConfig.LogLocation)) return;
                if (File.Exists(destFileFullName))
                {
                    File.Delete(destFileFullName);
                    File.Move(file.FullName, destFileFullName);
                }
                else
                    File.Move(file.FullName, destFileFullName);
            }
            catch (Exception ex)
            {
                Logger.Warn($"{file.FullName}备份文件失败,错误信息：{ex.Message}");
            }
        }

        /// <summary>
        /// 保存缓存记录
        /// </summary>
        public abstract void SaveRecord();

        /// <summary>
        /// 解析文件
        /// </summary>
        /// <param name="file"></param>
        /// <returns></returns>
        protected abstract bool LogProcessed(FileInfo file);

        /// <summary>
        /// 获取所有新文件
        /// </summary>
        /// <param name="directoryInfos"></param>
        /// <returns></returns>
        protected virtual List<FileInfo> GetNewFiles()
        {
            var files = GetFiles(Config.DataFileConfig.LogLocation, Config.Floor);
            if (!string.IsNullOrEmpty(Config.Extension)) files = files.Where(f => f.Extension.ToUpper() == Config.Extension.ToUpper()).ToList();
            return files.OrderBy(f => f.LastWriteTime).ToList();
        }

        /// <summary>
        /// 获取所有文件
        /// </summary>
        /// <param name="directoryInfos"></param>
        /// <returns></returns>
        private List<FileInfo> GetFiles(string directoryPath, int floor)
        {
            var result = new List<FileInfo>();
            try
            {
                List<DirectoryInfo> directoryInfos = GetDirectorys(directoryPath, floor);
                foreach (DirectoryInfo dir in directoryInfos)
                {
                    result.AddRange(dir.GetFiles());
                }
            }
            catch (Exception ex)
            {
                Logger.Warn($"获取文件失败:{ex.Message}");
            }
            return result.OrderBy(f => f.LastWriteTime).ToList();
        }

        /// <summary>
        /// 根据路径、层级获取所有文件夹
        /// </summary>
        /// <param name="directoryPath"></param>
        /// <param name="floor"></param>
        /// <returns></returns>
        private List<DirectoryInfo> GetDirectorys(string directoryPath, int floor)
        {
            var result = new List<DirectoryInfo>();
            if (Config.DataFileConfig.PathType == PathType.Share)
            {
                try
                {
                    var path = Config.DataFileConfig.LogLocation;
                    int startIndex = path.IndexOf("\\\\");
                    int endIndex = path.IndexOf('\\', startIndex + 2);
                    var ip = path.Substring(startIndex + 2, endIndex - startIndex - 2);
                    FolderAndFileHelper.ConnectShareFolder_Windows(ip, Config.DataFileConfig.UserName, Config.DataFileConfig.Password);
                }
                catch (Exception ex)
                {
                    Logger.Error($"获取共享文件ip地址失败：{ex}");
                }
            }
            if (!Directory.Exists(directoryPath))
            {
                Logger.Error($"连接地址失败：{directoryPath}");
                _isConnect = false;
                return result;
            }
            _isConnect = true;
            result.Add(new DirectoryInfo(directoryPath));
            int baseFloor = 1;
            if (floor > 1) baseFloor = floor;
            for (int i = 0; i < baseFloor - 1; i++)
            {
                var r = new List<DirectoryInfo>();
                foreach (DirectoryInfo dir in result)
                {
                    r.AddRange(dir.GetDirectories());
                }
                result = r;
            }
            return result;
        }

        /// <summary>
        /// 获取上次更新到的时间节点
        /// </summary>
        /// <returns></returns>
        protected abstract DateTime? GetLastUpdateTime();
    }
}